package com.example.project.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.example.project.utils.IpUtils;
import java.util.Collection;
import java.util.Map;

import jakarta.servlet.http.HttpServletRequest;

/**
 * 控制台请求日志记录处理 用于在控制台打印请求开始、参数内容和结束日志
 */
@Aspect
@Component
public class ConsoleLogAspect {

	private static final Logger log = LoggerFactory.getLogger(ConsoleLogAspect.class);

	/**
	 * 处理请求前执行 - 打印请求开始日志和参数内容
	 */
	@Before("execution(* com.example.project.controller..*.*(..))")
	public void doBefore(JoinPoint joinPoint) {
		try {
			HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
					.getRequest();

			// 获取请求信息
			String requestURI = request.getRequestURI();
			String requestMethod = request.getMethod();
			String remoteAddr = IpUtils.getIpAddr(request);

			// 获取方法信息
			String className = joinPoint.getTarget().getClass().getSimpleName();
			String methodName = joinPoint.getSignature().getName();

			Map<String, String[]> parameterMap = request.getParameterMap();
			
			// 获取参数信息并转换为参数名=参数值格式
			String params = convertParameterMapToString(parameterMap);

			// 打印请求开始日志
			log.info("======= START ==== 请求信息: {} {} {} =======", requestMethod, requestURI, remoteAddr);
			log.info("执行方法: {}.{}，URL参数: {}", className, methodName, params);

		} catch (Exception e) {
			log.warn("打印请求日志时发生异常: {}", e.getMessage());
		}
	}

	/**
	 * 处理完请求后执行 - 打印请求结束日志和返回结果
	 */
	@AfterReturning(pointcut = "execution(* com.example.project.controller..*.*(..))", returning = "result")
	public void doAfterReturning(JoinPoint joinPoint, Object result) {
		try {
			HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
					.getRequest();

			// 获取请求信息
			String requestURI = request.getRequestURI();
			String requestMethod = request.getMethod();

			// 获取方法信息
			String className = joinPoint.getTarget().getClass().getSimpleName();
			String methodName = joinPoint.getSignature().getName();

			// 处理返回结果 - 使用安全的方式描述结果
			String returnResult = "无返回结果";
			if (result != null) {
				try {
					returnResult = describeObjectSafely(result);
					// 如果结果描述太长，截取部分显示
					if (returnResult.length() > 200) {
						returnResult = returnResult.substring(0, 200) + "...";
					}
				} catch (Exception e) {
					// 如果描述失败，使用简单类名
					returnResult = result.getClass().getSimpleName() + "(描述失败)";
				}
			}

			// 打印请求结束日志
			log.info("======= END ==== 请求路径: {} {} 结果: {} =======", requestMethod, requestURI, returnResult);

		} catch (Exception e) {
			log.warn("打印结束日志时发生异常: {}", e.getMessage());
		}
	}

	/**
	 * 参数拼装 - 使用安全的方式处理参数，避免循环引用
	 */
	private String argsArrayToString(Object[] paramsArray) {
		StringBuilder params = new StringBuilder();
		if (paramsArray != null && paramsArray.length > 0) {
			for (int i = 0; i < paramsArray.length; i++) {
				Object param = paramsArray[i];
				if (param != null) {
					try {
						// 使用安全的方式描述参数，避免JSON序列化
						String paramDesc = describeObjectSafely(param);
						params.append("参数").append(i + 1).append(": ").append(paramDesc);
						if (i < paramsArray.length - 1) {
							params.append(", ");
						}
					} catch (Exception e) {
						// 如果描述失败，使用简单类名
						params.append("参数").append(i + 1).append(": ").append(param.getClass().getSimpleName());
						if (i < paramsArray.length - 1) {
							params.append(", ");
						}
					}
				}
			}
		}
		return params.toString();
	}

	/**
	 * 安全地描述对象，避免循环引用
	 */
	private String describeObjectSafely(Object obj) {
		if (obj == null) {
			return "null";
		}

		// 处理简单类型
		if (isSimpleType(obj)) {
			return obj.toString();
		}

		// 处理数组
		if (obj.getClass().isArray()) {
			return obj.getClass().getComponentType().getSimpleName() + "[]";
		}

		// 处理集合类型
		if (obj instanceof Collection) {
			Collection<?> collection = (Collection<?>) obj;
			return collection.getClass().getSimpleName() + "(size=" + collection.size() + ")";
		}

		// 处理Map类型
		if (obj instanceof Map) {
			Map<?, ?> map = (Map<?, ?>) obj;
			return map.getClass().getSimpleName() + "(size=" + map.size() + ")";
		}

		// 对于其他复杂对象，只显示类名和哈希值
		return obj.getClass().getSimpleName() + "@" + Integer.toHexString(obj.hashCode());
	}

	/**
	 * 判断是否为简单类型
	 */
	private boolean isSimpleType(Object obj) {
		return obj instanceof String || obj instanceof Number || obj instanceof Boolean || obj instanceof Character
				|| obj instanceof java.util.Date;
	}

	/**
	 * 将parameterMap转换为参数名=参数值格式的字符串
	 */
	private String convertParameterMapToString(Map<String, String[]> parameterMap) {
		if (parameterMap == null || parameterMap.isEmpty()) {
			return "无参数";
		}

		StringBuilder paramsBuilder = new StringBuilder();
		for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
			String paramName = entry.getKey();
			String[] paramValues = entry.getValue();
			
			if (paramValues != null && paramValues.length > 0) {
				// 如果参数有多个值，用逗号分隔
				String paramValue = String.join(",", paramValues);
				paramsBuilder.append(paramName).append("=").append(paramValue).append("; ");
			} else {
				paramsBuilder.append(paramName).append("=null; ");
			}
		}

		// 移除最后的分号和空格
		if (paramsBuilder.length() > 0) {
			paramsBuilder.setLength(paramsBuilder.length() - 2);
		}

		return paramsBuilder.toString();
	}
}
